home *** CD-ROM | disk | FTP | other *** search
/ Multimedia Jumpstart / Multimedia Microsoft Jumpstart Version 1.1a (Microsoft).BIN / develpmt / source / hotspot / vbx / drawhot.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-03  |  12.2 KB  |  457 lines

  1. /**************************************************************************
  2.  *
  3.  *  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  4.  *  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  5.  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  6.  *  PURPOSE.
  7.  *
  8.  *  Copyright (c) 1993  Microsoft Corporation.  All Rights Reserved.
  9.  * 
  10.  **************************************************************************/
  11.  
  12.  
  13. /*
  14.  * This file contains an AVI DrawProc, and various functions that the
  15.  * DrawProc calls (see the list of forward declars for a list of these
  16.  * functions; the ICAVIDrawProc is the only function visible outside
  17.  * this file).
  18.  *
  19.  * The drawproc draws red rectangles on an AVI to represent hotspots.
  20.  * The drawproc also slows down the AVI playback, because it copies the
  21.  * entire image onto a device-dependent bitmap for drawing the rectangles
  22.  *
  23.  */
  24.  
  25.  
  26. #include <windows.h>
  27. #include <windowsx.h>
  28. #include <vfw.h>
  29.  
  30. #include "hotspot.h"
  31.  
  32. // junk for AVIDrawGetInfo
  33. #define SZCODE char _based(_segname("_CODE"))
  34. static SZCODE szDescription[] = "Microsoft Hotspot Draw handler";
  35. static SZCODE szName[]        = "MS Hotspot";
  36. #define FOURCC_AVIDraw      mmioFOURCC('H','O','T','T')
  37. #define VERSION_AVIDraw     0x00010000
  38. #ifndef HUGE
  39. #define HUGE _huge
  40. #endif
  41.  
  42. // this is the structure that video for windows hangs on to for us.
  43. // We allocate it and give vfw a pointer when the drawproc is
  44. // opened, and it gives it back while the frames are being drawn.
  45. // We store such things as our DC and our pen to draw the rectangles
  46. // with in here.
  47. typedef struct
  48. {
  49.     HDRAWDIB            hdd;
  50.     HDC                 hdc;
  51.     int                 xDst;
  52.     int                 yDst;
  53.     int                 dxDst;
  54.     int                 dyDst;
  55.     int                 xSrc;
  56.     int                 ySrc;
  57.     int                 dxSrc;
  58.     int                 dySrc;
  59.     HBITMAP                hddb;
  60.     HDC                    hMemdc;
  61.     HBITMAP                hOldbmp;
  62.     HBRUSH                hBrush;
  63.     HBRUSH                hOldBrush;
  64.     HPEN                hPen;
  65.     HPEN                hOldPen;
  66.     PMOVIEINFO            lpMovie;
  67. } INSTINFO, FAR * PINSTINFO;
  68.  
  69. // forward declars
  70. LONG FAR PASCAL _export ICAVIDrawProc(DWORD id, HDRVR hDriver,
  71.     UINT uiMessage, LPARAM lParam1, LPARAM lParam2);
  72. static LONG NEAR PASCAL AVIDrawOpen(ICOPEN FAR * icopen);
  73. static LONG NEAR PASCAL AVIDrawClose(PINSTINFO pi);
  74. static LONG NEAR PASCAL AVIDrawGetInfo(ICINFO FAR *icinfo, LONG lSize);
  75. static LONG NEAR PASCAL AVIDrawQuery(PINSTINFO pi, LPBITMAPINFOHEADER lpbiIn);
  76. static LONG NEAR PASCAL AVIDrawSuggestFormat(PINSTINFO pi, ICDRAWSUGGEST FAR *lpicd, LONG cbicd);
  77. static LONG NEAR PASCAL AVIDrawBegin(PINSTINFO pi, ICDRAWBEGIN FAR *lpicd, LONG cbicd);
  78. static LONG NEAR PASCAL AVIDraw(PINSTINFO pi, ICDRAW FAR *lpicd, LONG cbicd);
  79. static LONG NEAR PASCAL AVIDrawEnd(PINSTINFO pi);
  80. static LONG NEAR PASCAL AVIDrawChangePalette(PINSTINFO pi, LPBITMAPINFOHEADER lpbi);
  81.  
  82. // macros used by DIB stuff.
  83. // hey, we're not using DIB stuff anymore...
  84. #define WIDTHBYTES(i)     ((unsigned)((i+31)&(~31))/8)
  85. #define DIBWIDTHBYTES(bi) (DWORD)WIDTHBYTES((int)(bi).biWidth * (int)(bi).biBitCount)
  86.  
  87. // Here we create a device-dependent bitmap in memory to draw into.
  88. // We'll copy the DIB onto this bitmap, draw rects on it, then copy
  89. // the result to the screen.  This can be done more efficiently using
  90. // the DIB driver that comes with Windows 3.1, if anybody wants to 
  91. // recode it...
  92. // We also create our red pen here, as well as a brush for doing
  93. // =hollow= rectangles
  94. void CreateMemoryDC(PINSTINFO pi)
  95. {
  96.     LOGBRUSH lb;
  97.     
  98.     pi->hddb = CreateCompatibleBitmap(pi->hdc,pi->dxDst,pi->dyDst);
  99.     pi->hMemdc = CreateCompatibleDC(pi->hdc);
  100.     pi->hOldbmp = SelectObject(pi->hMemdc,pi->hddb);
  101.     lb.lbStyle = BS_NULL;
  102.     pi->hBrush = CreateBrushIndirect(&lb);
  103.     pi->hOldBrush = SelectObject(pi->hMemdc,pi->hBrush);
  104.     pi->hPen = CreatePen(PS_SOLID,0,RGB(255,0,0));
  105.     pi->hOldPen = SelectObject(pi->hMemdc,pi->hPen);
  106. }
  107.  
  108. // here we undo everything CreateMemoryDC did.
  109. void DisintegrateMemoryDC(PINSTINFO pi)
  110. {
  111.     SelectObject(pi->hMemdc,pi->hOldPen);
  112.     DeleteObject(pi->hPen);
  113.     SelectObject(pi->hMemdc,pi->hOldBrush);
  114.     DeleteObject(pi->hBrush);
  115.     SelectObject(pi->hMemdc,pi->hOldbmp);
  116.     DeleteObject(pi->hddb);
  117.     DeleteDC(pi->hMemdc);
  118. }
  119.  
  120. // this is the drawproc that vfw calls.  It basically just hands
  121. // stuff off to other functions later in this file.  A few things
  122. // are handled here.  This is message-handling proc just like a
  123. // Window Proc or a VBX Control Proc...
  124. LONG FAR PASCAL _export ICAVIDrawProc(DWORD id, HDRVR hDriver,
  125.     UINT uiMessage, LPARAM lParam1, LPARAM lParam2)
  126. {
  127.     PINSTINFO pi = (PINSTINFO)id;
  128.  
  129.     switch (uiMessage)
  130.     {
  131.     case DRV_LOAD:
  132.     case DRV_FREE:
  133.         return 1;
  134.     case DRV_OPEN:
  135.         if (lParam2 == 0L)
  136.         {
  137.             return 1;
  138.         }
  139.         return AVIDrawOpen((ICOPEN FAR *)lParam2);
  140.     case DRV_CLOSE:
  141.         return AVIDrawClose(pi);
  142.     case DRV_QUERYCONFIGURE:
  143.         return 0;
  144.     case DRV_CONFIGURE:
  145.         return 1;
  146.     case ICM_CONFIGURE:
  147.     case ICM_ABOUT:
  148.         return ICERR_UNSUPPORTED;
  149.     case ICM_GETSTATE:
  150.         return 0L;
  151.     case ICM_GETINFO:
  152.         return AVIDrawGetInfo((ICINFO FAR *)lParam1, lParam2);
  153.     case ICM_DRAW_QUERY:
  154.         return AVIDrawQuery(pi, (LPBITMAPINFOHEADER)lParam1);
  155.     case ICM_DRAW_SUGGESTFORMAT:
  156.         return AVIDrawSuggestFormat(pi, (ICDRAWSUGGEST FAR *) lParam1, lParam2);
  157.     case ICM_DRAW_BEGIN:
  158.         return AVIDrawBegin(pi, (ICDRAWBEGIN FAR *) lParam1, lParam2);
  159.     case ICM_DRAW_REALIZE:
  160.         pi->hdc = (HDC) lParam1;
  161.         if (!pi->hdc || !pi->hdd)
  162.             break;
  163.         return DrawDibRealize(pi->hdd, pi->hdc, (BOOL) lParam2);
  164.     case ICM_DRAW_GET_PALETTE:
  165.         if (!pi->hdd)
  166.             break;
  167.         return (LONG) (UINT) DrawDibGetPalette(pi->hdd);
  168.     case ICM_DRAW:
  169.         return AVIDraw(pi, (ICDRAW FAR *)lParam1, lParam2);
  170.     case ICM_DRAW_CHANGEPALETTE:
  171.         return AVIDrawChangePalette(pi, (LPBITMAPINFOHEADER) lParam1);
  172.     case ICM_DRAW_END:
  173.         return AVIDrawEnd(pi);
  174.     case DRV_DISABLE:
  175.     case DRV_ENABLE:
  176.         return 1;
  177.     case DRV_INSTALL:
  178.     case DRV_REMOVE:
  179.         return 1;
  180.     }
  181.     if (uiMessage < DRV_USER)
  182.     {
  183.         return DefDriverProc(id,hDriver,uiMessage,lParam1,lParam2);
  184.     }
  185.     else
  186.     {
  187.         return ICERR_UNSUPPORTED;
  188.     }
  189. }
  190.  
  191. // This basically allocates our "instance info" (that struct defined
  192. // at the beginning of this file).
  193. static LONG NEAR PASCAL AVIDrawOpen(ICOPEN FAR * icopen)
  194. {
  195.     PINSTINFO pinst;
  196.  
  197.     if (icopen->fccType != streamtypeVIDEO)
  198.     {
  199.         return 0;
  200.     }
  201.     if (icopen->dwFlags == ICMODE_COMPRESS)
  202.     {
  203.         return 0;
  204.     }
  205.     if (icopen->dwFlags == ICMODE_DECOMPRESS)
  206.     {
  207.         return 0;
  208.     }
  209.     pinst = (PINSTINFO)GlobalAllocPtr(GHND, sizeof(INSTINFO));
  210.     if (!pinst)
  211.     {
  212.         icopen->dwError = ICERR_MEMORY;
  213.         return NULL;
  214.     }
  215.     pinst->hdd = DrawDibOpen();
  216.     pinst->hddb = NULL;
  217.     icopen->dwError = ICERR_OK;
  218.     return (LONG) pinst;
  219. }
  220.  
  221. // This frees our instance structure, and everything within the
  222. // structure.
  223. static LONG NEAR PASCAL AVIDrawClose(PINSTINFO pi)
  224. {
  225.     if (pi->hdd)
  226.     {
  227.         DrawDibClose(pi->hdd);
  228.     }
  229.     if (pi->hddb)
  230.     {
  231.         DisintegrateMemoryDC(pi);
  232.     }
  233.     GlobalFreePtr(pi);
  234.     return 1;
  235. }
  236.  
  237. // When AVI gets nosy, it goes here.  We pass it those strings and
  238. // stuff defined at the top of this file.
  239. static LONG NEAR PASCAL AVIDrawGetInfo(ICINFO FAR *icinfo, LONG lSize)
  240. {
  241.     if (icinfo == NULL)
  242.     {
  243.         return sizeof(ICINFO);
  244.     }
  245.     if (lSize < sizeof(ICINFO))
  246.     {
  247.         return 0;
  248.     }
  249.     icinfo->dwSize        = sizeof(ICINFO);
  250.     icinfo->fccType        = ICTYPE_VIDEO;
  251.     icinfo->fccHandler      = FOURCC_AVIDraw;
  252.     icinfo->dwFlags        = VIDCF_DRAW;
  253.     icinfo->dwVersion       = VERSION_AVIDraw;
  254.     icinfo->dwVersionICM    = ICVERSION;
  255.     lstrcpy(icinfo->szDescription, szDescription);
  256.     lstrcpy(icinfo->szName, szName);
  257.     return sizeof(ICINFO);
  258. }
  259.  
  260. // Make sure we can handle the format given.
  261. static LONG NEAR PASCAL AVIDrawQuery(PINSTINFO pi,
  262.     LPBITMAPINFOHEADER lpbiIn)
  263. {
  264.     if (lpbiIn == NULL)
  265.     {
  266.         return ICERR_BADFORMAT;
  267.     }
  268.     if (lpbiIn->biCompression != BI_RGB)
  269.     {
  270.         return ICERR_BADFORMAT;
  271.     }
  272.     return ICERR_OK;
  273. }
  274.  
  275. // suggest BI_RGB
  276. static LONG NEAR PASCAL AVIDrawSuggestFormat(PINSTINFO pi,
  277.     ICDRAWSUGGEST FAR *lpicd, LONG cbicd)
  278. {
  279.     HIC hic;
  280.  
  281.     if (lpicd->lpbiSuggest == NULL)
  282.     {
  283.         return sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD);
  284.     }
  285.     hic = ICGetDisplayFormat(NULL, lpicd->lpbiIn, lpicd->lpbiSuggest,
  286.         0, lpicd->dxDst, lpicd->dyDst);
  287.     if (hic)
  288.     {
  289.         ICClose(hic);
  290.     }
  291.     if (lpicd->lpbiSuggest)
  292.     {
  293.         if (lpicd->lpbiSuggest->biCompression == BI_RLE8)
  294.         {
  295.             lpicd->lpbiSuggest->biCompression = BI_RGB;
  296.         }
  297.     }
  298.     return sizeof(BITMAPINFOHEADER) + lpicd->lpbiSuggest->biClrUsed * sizeof(RGBQUAD);
  299. }
  300.  
  301. // Here, we grab DC's and stuff from vfw and stash it into our own
  302. // instance info.  We also get our movieinfo, which is the structure
  303. // that has the actual hotspots in it.  It's in a global variable, even
  304. // though I don't like global variables...
  305. static LONG NEAR PASCAL AVIDrawBegin(PINSTINFO pi, ICDRAWBEGIN FAR *lpicd, LONG cbicd)
  306. {
  307.     LONG    l;
  308.  
  309.     l = AVIDrawQuery(pi, lpicd->lpbi);
  310.     if ((l != 0) || (lpicd->dwFlags & ICDRAW_QUERY))
  311.     {
  312.         return l;
  313.     }
  314.     pi->hdc = lpicd->hdc;
  315.     pi->xDst = lpicd->xDst;
  316.     pi->yDst = lpicd->yDst;
  317.     pi->dxDst = lpicd->dxDst;
  318.     pi->dyDst = lpicd->dyDst;
  319.     pi->xSrc = lpicd->xSrc;
  320.     pi->ySrc = lpicd->ySrc;
  321.     pi->dxSrc = lpicd->dxSrc;
  322.     pi->dySrc = lpicd->dySrc;
  323.     SetStretchBltMode(pi->hdc, COLORONCOLOR);
  324.     if (!DrawDibBegin(pi->hdd, pi->hdc,
  325.             pi->dxDst, pi->dyDst,
  326.             lpicd->lpbi,
  327.             pi->dxSrc, pi->dySrc,
  328.             0))
  329.     {
  330.         return ICERR_UNSUPPORTED;
  331.     }
  332.     if (pi->hddb)
  333.     {
  334.         DisintegrateMemoryDC(pi);
  335.     }
  336.     CreateMemoryDC(pi);
  337.     {
  338.         WORD    high;
  339.         WORD    low;
  340.         
  341.         high = GetProp(lpicd->hwnd,"DataHi");
  342.         low = GetProp(lpicd->hwnd,"DataLo");
  343.         pi->lpMovie = (PMOVIEINFO) (MAKELONG(low,high));
  344.     }
  345.     return ICERR_OK;
  346. }
  347.  
  348.  
  349. // Several interesting things happen here:  1) We copy the DIB onto
  350. // our own bitmap (hMemDC), with DrawDibDraw, then we draw rectangles
  351. // onto that bitmap (or not) as we walk down the hotspot list (with
  352. // Rectangle), then we BitBlt the result onto the screen.  I've heard
  353. // rumors that this could be done with the DIB driver and get rid of
  354. // the extra image copy.
  355. static LONG NEAR PASCAL AVIDraw(PINSTINFO pi, ICDRAW FAR *lpicd, LONG cbicd)
  356. {
  357.     UINT  wFlags;
  358.  
  359.     wFlags = DDF_SAME_HDC;
  360.     if ((lpicd->dwFlags & ICDRAW_NULLFRAME) || lpicd->lpData == NULL)
  361.     {
  362.         if (lpicd->dwFlags & ICDRAW_UPDATE)
  363.         {
  364.             wFlags |= DDF_UPDATE;
  365.         }
  366.         else
  367.         {
  368.             return ICERR_OK;
  369.         }
  370.     }
  371.     if (lpicd->dwFlags & ICDRAW_PREROLL)
  372.     {
  373.         wFlags |= DDF_DONTDRAW;
  374.     }
  375.     if (lpicd->dwFlags & ICDRAW_HURRYUP)
  376.     {
  377.         wFlags |= DDF_HURRYUP;
  378.     }
  379.     if (pi->lpMovie && pi->lpMovie->bShowHot)
  380.     {
  381.         if(DrawDibDraw(pi->hdd, pi->hMemdc,
  382.                 0,0,
  383.                 pi->dxDst, pi->dyDst,
  384.                 lpicd->lpFormat,
  385.                 lpicd->lpData,
  386.                 pi->xSrc, pi->ySrc,
  387.                 pi->dxSrc, pi->dySrc,
  388.                 wFlags))
  389.         {
  390.             PHOTSPOT pHotspot;
  391.             pHotspot = (pi->lpMovie)->pHotspotList;
  392.             while (pHotspot)
  393.             {
  394.                 if ((pHotspot->BeginFrame <
  395.                         lpicd->lTime+1+(pi->lpMovie)->lLastSeek) &&
  396.                         (pHotspot->EndFrame+1 >
  397.                         lpicd->lTime+(pi->lpMovie)->lLastSeek))
  398.                 {
  399.                     Rectangle(pi->hMemdc,
  400.                         pHotspot->rc.left,
  401.                         pHotspot->rc.top,
  402.                         pHotspot->rc.right,
  403.                         pHotspot->rc.bottom);
  404.                 }
  405.                 pHotspot = pHotspot->pNext;
  406.             }
  407.             BitBlt(pi->hdc,pi->xDst,pi->yDst,pi->dxDst,pi->dyDst,
  408.                 pi->hMemdc,0,0,SRCCOPY);
  409.         }
  410.     }
  411.     else if (!DrawDibDraw(pi->hdd, pi->hdc,
  412.             pi->xDst, pi->yDst,
  413.             pi->dxDst, pi->dyDst,
  414.             lpicd->lpFormat,
  415.             lpicd->lpData,
  416.             pi->xSrc, pi->ySrc,
  417.             pi->dxSrc, pi->dySrc,
  418.             wFlags))
  419.     {
  420.         if (wFlags & DDF_UPDATE)
  421.         {
  422.             return ICERR_CANTUPDATE;
  423.         }
  424.         else
  425.         {
  426.             return ICERR_UNSUPPORTED;
  427.         }
  428.     }
  429.     return ICERR_OK;
  430. }
  431.  
  432. // Echo the pallette back to vfw with DrawDibChangePallette
  433. static LONG NEAR PASCAL AVIDrawChangePalette(PINSTINFO pi, LPBITMAPINFOHEADER lpbi)
  434. {
  435.     PALETTEENTRY    ape[256];
  436.     LPRGBQUAD        lprgb;
  437.     int i;
  438.     
  439.     lprgb = (LPRGBQUAD) ((LPBYTE) lpbi + lpbi->biSize);
  440.     for (i = 0; i < (int) lpbi->biClrUsed; i++)
  441.     {
  442.         ape[i].peRed = lprgb[i].rgbRed;
  443.         ape[i].peGreen = lprgb[i].rgbGreen;
  444.         ape[i].peBlue = lprgb[i].rgbBlue;
  445.         ape[i].peFlags = 0;
  446.     }
  447.     DrawDibChangePalette(pi->hdd, 0, (int) lpbi->biClrUsed,
  448.         (LPPALETTEENTRY)ape);
  449.     return ICERR_OK;
  450. }
  451.  
  452. // Everything is freed in AVIDrawClose, nothing to do here...
  453. static LONG NEAR PASCAL AVIDrawEnd(PINSTINFO pi)
  454. {
  455.     return ICERR_OK;
  456. }
  457.